
<template>
  <div class="treeSelect">
    <el-select
      :value="valueTitle"
      :multiple="multiple"
      :collapse-tags="collapse"
      :clearable="clearable"
      :disabled="disabled"
      :size="size"
      :style="selectStyle"
      @input="$emit('input', $event)"
      @clear="handleClear"
      @remove-tag="handleRemoveTag"
    >
      <el-option :value="valueId" :label="label">
        <el-tree
          id="tree-option"
          ref="selectTree"
          :accordion="accordion"
          :show-checkbox="multiple"
          :data="options"
          :props="treeProps"
          :node-key="treeProps.id"
          :check-strictly="checkStrictly"
          :default-expand-all="expand"
          :auto-expand-parent="expandParent"
          :expand-on-click-node="expandNode"
          :default-expanded-keys="defaultExpandedKeys"
          @node-click="handleNodeClick"
          @check-change="handleCheckChange"
        >
        </el-tree>
      </el-option>
    </el-select>
  </div>
</template>



<style lang="scss" scoped>
.el-scrollbar .el-scrollbar__view .el-select-dropdown__item {
  height: auto;
  // max-height: 274px;
  padding: 0;
  overflow: hidden;
  // overflow: hidden;
  // overflow-y: auto;
}

.el-scrollbar .el-select-dropdown__item.selected {
  font-weight: normal;
}

// 横向滚动条
.el-scrollbar__bar.is-horizontal {
  height: 6px;
  left: 2px;
}
// 纵向滚动条
.el-scrollbar__bar.is-vertical {
  width: 6px;
  top: 2px;
}

// 字体和大小
.custom-tree-node {
  font-family: "Microsoft YaHei";
  font-size: 14px;
  position: relative;
}

// 原生el-tree-node的div是块级元素，需要改为inline-block，才能显示滚动条
.treeSelect .el-tree > .el-tree-node {
  display: inline-block;
  min-width: 100%;
}

// ul li ::v-deep .el-tree .el-tree-node__content {
//   height: auto;
//   padding: 0 20px;
// }

// .el-tree-node__label {
//   font-weight: normal;
// }

.el-tree ::v-deep .is-current .el-tree-node__label {
  color: #1b65b9;
  font-weight: 700;
}

.el-tree ::v-deep .is-current .el-tree-node__children .el-tree-node__label {
  color: #606266;
  font-weight: normal;
}
</style>


<script>
export default {
  name: "tree-select",
  props: {
    // 是否可多选，默认单选
    multiple: {
      type: Boolean,
      default: false,
    },
    // 可清空选项
    clearable: {
      type: Boolean,
      default: () => {
        return true;
      },
    },
    // -------------------- el-tree --------------------
    // 配置项
    treeProps: {
      type: Object,
      default: () => {
        return {
          id: "id", // ID字段名
          label: "title", // 显示名称
          children: "children", // 子级字段名
        };
      },
    },
    // 选项列表数据(树形结构的对象数组)
    options: {
      type: Array,
      default: () => {
        return [];
      },
    },
    // 自动收起
    accordion: {
      type: Boolean,
      default: () => {
        return false;
      },
    },
    // 在显示复选框的情况下，是否严格的遵循父子不互相关联的做法，默认为 false
    checkStrictly: {
      type: Boolean,
      default: () => {
        return false;
      },
    },
    // 是否展开所有节点，默认展开
    expand: {
      type: Boolean,
      default() {
        return true;
      },
    },
    // 展开子节点的时候是否自动展开父节点 默认值为 true
    expandParent: {
      type: Boolean,
      default() {
        return true;
      },
    },
    // 是否在点击节点的时候展开或者收缩节点， 默认值为 true，如果为 false，则只有点箭头图标的时候才会展开或者收缩节点。
    expandNode: {
      type: Boolean,
      default() {
        return true;
      },
    },
    // -------------------- el-select --------------------
    // 初始值 - 绑定value是为了外面也可以传值改变到里面的值双向绑定
    value: {
      type: [String, Number, Boolean, Array],
      default: () => {
        return null;
      },
    },
    // 多选时是否将选中值按文字的形式展示
    collapse: {
      type: Boolean,
      default: false,
    },
    // 选择框大小
    size: {
      type: String,
      default: () => {
        return "small"; // medium large
      },
    },
    // 选择框 宽度
    width: {
      type: String,
      default: "270px",
    },
    // 是否禁用
    disabled: {
      type: Boolean,
      default: () => {
        return false;
      },
    },
  },
  data() {
    return {
      valueId: this.value, // 初始值
      valueTitle: "",
      label: "", // 分组
      defaultExpandedKeys: [],
    };
  },
  mounted() {
    this.initHandle();
  },
  methods: {
    /**
     * @description: 初始化组件
     * @param {*}
     * @return {*}
     */
    initHandle() {
      // 单选
      if (this.valueId && !this.multiple) {
        var node = this.$refs.selectTree.getNode(this.valueId);
        if (node) {
          this.valueTitle = node.data[this.treeProps.label]; // 初始化显示
          this.defaultExpandedKeys = [this.valueId]; // 设置默认展开
          this.$nextTick(() => {
            this.$refs.selectTree.setCurrentKey(this.valueId); // 设置默认选中
          });
        }
      }
      // 多选
      if (this.valueId && this.multiple) {
        this.defaultExpandedKeys = this.valueId; // 设置默认展开
        this.$nextTick(() => {
          this.$refs.selectTree.setCheckedKeys(this.valueId); // 设置默认选中
        });
      }
    },
    /**
     * @description: 单选 - 节点被点击时的回调,返回被点击的节点数据
     * @param {*}
     * @return {*}
     */
    handleNodeClick(node) {
      this.valueTitle = node[this.treeProps.label];
      this.valueId = node[this.treeProps.id];
      this.defaultExpandedKey = [];
      this.$emit("getValue", this.valueId, this.valueTitle);
    },
    /**
     * @description: 多选，节点勾选状态发生变化时的回调
     * @param {*}
     * @return {*}
     */
    handleCheckChange(data, checked) {
      let currentNode = this.$refs.selectTree.getNode(data);
      if (this.checkStrictly) {
        // 用于：父子节点严格互不关联时，父节点勾选变化时通知子节点同步变化，实现单向关联
        if (checked) {
          // 选中 子节点只要被选中父节点就被选中
          this.parentNodeChange(currentNode);
        } else {
          // 未选中 处理子节点全部未选中
          this.childNodeChange(currentNode);
        }
      }
      // 用于：父子节点严格关联时
      // console.log(this.$refs.selectTree.getHalfCheckedKeys())
      this.valueId = this.$refs.selectTree.getCheckedKeys();
      var checkedNodes = this.$refs.selectTree.getCheckedNodes();
      this.valueTitle = checkedNodes.map((node) => {
        return node[this.treeProps.label];
      });
      this.defaultExpandedKeys = [];
      this.$emit("getValue", this.valueId, this.valueTitle);
    },
    /**
     * @description: 清除选中
     * @param {*}
     * @return {*}
     */
    handleClear() {
      this.valueTitle = "";
      this.valueId = "";
      this.defaultExpandedKeys = [];
      // 清除树
      if (this.multiple) {
        this.$refs.selectTree.setCheckedKeys(null);
      } else {
        this.$refs.selectTree.setCurrentKey(null);
      }
      this.$emit("getValue", null);
    },
    /**
     * @description: 多选 删除任一标签选项的回调
     * @param {*}
     * @return {*}
     */
    handleRemoveTag(val) {
      var checkedNodes = this.$refs.selectTree.getCheckedNodes();

      var node = checkedNodes.find(
        (node) => node[this.treeProps.label] === val
      );
      this.$refs.selectTree.setChecked(node[this.treeProps.id], false);
    },
    // 统一处理子节点为不选中
    childNodeChange(node) {
      for (let i = 0; i < node.childNodes.length; i++) {
        node.childNodes[i].checked = false;
        this.childNodeChange(node.childNodes[i]);
      }
    },
    // 统一处理父节点为选中
    parentNodeChange(node) {
      if (node.parent.key !== undefined) {
        node.parent.checked = true;
        this.parentNodeChange(node.parent);
      }
    },
  },
  watch: {
    value() {
      this.valueId = this.value;
      this.initHandle();
    },
    // 父子组件双向绑定value
    valueId() {
      this.$emit("input", this.valueId);
    },
  },
  computed: {
    selectStyle() {
      return {
        width: `${this.width}`,
      };
    },
  },
};
</script>


